package org.example.java_gobang.game;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.example.java_gobang.JavaGobangApplication;
import org.example.java_gobang.model.User;
import org.example.java_gobang.model.UserMapper;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

//创建房间
@Data
public class Room {
    //房间ID:
    private String roomId;
    //房间中的两个游戏玩家:
    private User user1;
    private User user2;
    //执白棋玩家,先手
    private int whiteUser;

    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;
    //创建一个棋盘数组
    //规定:0:未落子,1:玩家1下的子,2:玩家2下的子
    //这里设置三种状态是因为要根据玩家的下子情况,判断是否分出胜负
    private int[][] board = new int[MAX_ROW][MAX_COL];

    private ObjectMapper objectMapper = new ObjectMapper();

//    @Autowired
    private OnlineUserManager onlineUserManager ;

    private RoomManager roomManager;

    private UserMapper userMapper;

    public Room(){
        //生成游戏房间唯一ID:
        UUID uuid = UUID.randomUUID();
        roomId = uuid.toString();
        //由于Room已经通过手动管理起来了,不能再注入到Spring中,
        //在需要使用spring中的管理类时,无法通过@Autowired注入,还可以通过手动获取的方式.
        //通过入口类记录的context,手动获取前面的RoomManager和OnlineUserManager
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }
    //这个方法用来处理 房间中的一次落子操作
    public void putChess(String reqJson) throws IOException {
        //1.记录当前落子位置
        GameRequest request = objectMapper.readValue(reqJson, GameRequest.class);
        // 2 . 判断当前落子是谁下的:
        int chess = request.getUserId() == user1.getUserId()?1:2;
        // 3. 获取落子位置
        int row = request.getRow();
        int col = request.getCol();
        // 4 . 判断当前位置是否已经下过:
        if(board[row][col]!=0){
            System.out.println("当前位置:("+row+","+col+")已经有子了");
            return;
        }
        //5 . 进行下子:
        board[row][col] = chess;
        //打印棋盘信息,方便后续的调试维护
        printBoard();

        //6 . 判断是否已有玩家胜出:
        int winner = checkWinner(row,col,chess);
        //7.将信息返回给房间中的所有客户
        //创建落子响应对象
        GameResponse resp = new GameResponse();
        resp.setMessage("putChess");
        resp.setUserId(request.getUserId());
        resp.setRow(row);
        resp.setCol(col);
        resp.setWinner(winner);
        //通过onlineUserManager , 获取用户的websocketSession
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
       //这里进行特殊处理:当检查到会话为空时,判定为玩家已经下线,直接判定另一方获胜
        if(session1==null){
            //玩家1已经下线:
            resp.setWinner(user2.getUserId());
            System.out.println("玩家1掉线!");
        }
        if(session2==null){
            //玩家2下线:
            resp.setWinner(user1.getUserId());
            System.out.println("玩家2掉线!");
        }
        //将响应信息分别进行传输:
        if(session1!=null){
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
        }
        if(session2!=null){
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
        }
        //当已经分出胜负时,游戏结束,游戏房间就要被销毁,将房间从房间管理器中移除
        if(resp.getWinner()!=0){
            //以分出胜负
            System.out.println("已分出胜负,游戏房间即将销毁:roomId="+roomId+",获胜方为 :"+resp.getWinner());
            //更新获胜方和失败方的信息:
            userMapper.userWin(resp.getWinner());
            userMapper.userLose(resp.getWinner()==user1.getUserId()?user2.getUserId():user1.getUserId());
            //销毁房间:将游戏房间从房间管理器中移除:
            roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
        }
    }

//   在控制台 打印棋盘信息,
    private void printBoard() {
        System.out.println("棋盘信息: "+roomId);
        System.out.println("========================================");
        for(int i=0;i<MAX_ROW;i++){
            for(int j=0;j<MAX_COL;j++){
                System.out.print(board[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println("========================================");
    }

    private int checkWinner(int row, int col, int chess) {
        //判断一行是否可以构成5子连珠
        for(int c=col-4;c<=col;c++){
            //当出现下标越界时,这里直接抛出异常,跳过此次判断,并继续向后判断即可:
            try{
                if(board[row][c]==chess
                    && board[row][c+1]==chess
                    && board[row][c+2]==chess
                    && board[row][c+3]==chess
                    && board[row][c+4]==chess){
                    System.out.println("胜负已分,获胜方为: "+ (chess==1?user1.getUserId():user2.getUserId()));
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch(IndexOutOfBoundsException e){
                continue;
            }
        }
        //检查一列是否构成5子连珠
        for(int r=row-4;r<=row;r++){
            try{
                if(board[r][col]==chess
                && board[r+1][col]==chess
                && board[r+2][col]==chess
                && board[r+3][col]==chess
                && board[r+4][col]==chess){
                    System.out.println("胜负已分,获胜方为: "+ (chess==1?user1.getUserId():user2.getUserId()));
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch(IndexOutOfBoundsException e){
                continue;
            }
        }
        //检查左对角线是否构成5子连珠
        for(int r=row-4,c= col-4;r<=row && c<=col;r++,c++){
            try{
                if(board[r][c]==chess
                && board[r+1][c+1]==chess
                && board[r+2][c+2]==chess
                && board[r+3][c+3]==chess
                && board[r+4][c+4]==chess){
                    System.out.println("胜负已分,获胜方为: "+ (chess==1?user1.getUserId():user2.getUserId()));
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch(IndexOutOfBoundsException e){
                continue;
            }
        }
        //检查右对角线是否构成5子连珠
        for(int r = row-4,c = col+4 ;r<=row && c>=col;r++,c--){
            try{
                if(board[r][c]==chess
                && board[r+1][c-1]==chess
                && board[r+2][c-2]==chess
                && board[r+3][c-3]==chess
                && board[r+4][c-4]==chess){
                    System.out.println("胜负已分,获胜方为: "+ (chess==1?user1.getUserId():user2.getUserId()));
                    return chess==1?user1.getUserId():user2.getUserId();
                }
            }catch(ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        //胜负未分出来,直接返回0:
        return 0;
    }
}
